let Vue; //通过插件传递过来
// 2.VueRouter类
export default class VueRouter {
  constructor(options) {
    //   因为会接收到routes的路由配置，所以要创建一个对象map将关系保存下来.之后一一对应
    // map会将path的key值和组件的构造函数component对应起来
    // const router = new VueRouter({
    //     routes
    //   });
    this.$options = options;
    // 将options保存下来
    this.routerMap = {};
    // 需要一个current变量，将来会保存url hash后面的地址，需要实现
    // 响应式 因为当地址变得时候,对应的组件也要响应的变化起来
    // 需要在data里声明一个属性,实现响应式\
    // vue使其变成响应式的
    this.app = new Vue({
      data: {
        current: "/"
      }
    });
  }
  init() {
    //   1.事件的监听
    this.bindEvents();
    // 2.创建路由的映射
    this.createRouteMap();
    // 3.声明两个全局组件<router-view></router-view>  <router-link></router-link>
    this.initComponent();
  }
  bindEvents() {
    window.addEventListener("hashchange", this.onHashChange.bind(this));
    //   页面刚刚加载的时候也要执行一下load这个事件
    window.addEventListener("load", this.onHashChange.bind(this));
  }
  onHashChange() {
    //   拿到路由地址#/about
    this.app.current = window.location.hash.slice(1) || "/";
  }
  //   解析routes选项
  createRouteMap() {
    this.$options.routes.forEach(item => {
      this.routerMap[item.path] = item.component;
    });
  }
  //   声明两个组件
  initComponent() {
    // 全局声明组件
    // Vue.component('router-link)
    Vue.component("router-link", {
      //传递属性
      props: { to: { type: String, required: true } },
      render(h) {
        //   render函数是生成虚拟dom，
        // 描述渲染真实dom<a to="/">***</a>
        // h(tag,data,children)
        //   return <a href={this.to}>{this.$slots.default}</a>
        return h("a", { attrs: { href: this.to } }, [this.$slots.default]); //匿名插槽
      }
    });
    Vue.component("router-view", {
      render: h => {
        //this指向VueRouter实例
        const component = this.routerMap[this.app.current];
        return h(component);
      }
    });
  }
}
// 插件要求实现install方法即可
// function中接收的参数是vue的构造函数
VueRouter.install = function(_Vue) {
  Vue = _Vue;
  // 把这个Vue的构造函数_Vue传递给上面的Vue
  // Vue.use()以后，上面的Let Vue就有了真实的
  //   之后再new Vue的时候就创造了Vue（this.app = new Vue({})）的新的实例

  // 混入：挂载$router
  //   意思是接下来的代码在每个组件的beforeCreate的时候都要执行一下
  Vue.mixin({
    beforeCreate() {
      // this指当前组件的实例，是任何组件有可能
      //   如果选项中有router，说明是跟组件，这个时候，要将router挂载
      if (this.$options.router) {
        //  this.$options.router全局唯一的根的路由器的实例
        Vue.prototype.$router = this.$options.router;
        // 这样每一个子组件都有this.$router可以使用了
        // 初始化router
        this.$options.router.init();
      }
    }
  }); //全局混入
};
